home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 46 / Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso / -serious- / programming / other / gtdrag / examples / boopsi.c < prev    next >
C/C++ Source or Header  |  1999-09-06  |  16KB  |  542 lines

  1. ;/* boopsi.c - Test for the gtdrag.library, 7.6.1999
  2. ;**
  3. ;** Copyright ©1999 pinc Software.
  4. ;** All rights reserved.
  5. ;**
  6. sc boopsi.c lib:debug.lib nodbg nostkchk link ign=73 to=ram:boopsi
  7. run ram:boopsi
  8. quit
  9. */
  10.  
  11.  
  12. /* This example shows how to create a custom (BOOPSI) gadget
  13. ** with support for drag&drop.
  14. **
  15. ** It's a very simple example but you may use this code to produce
  16. ** one at your own.
  17. **
  18. ** Although I tried hardly to not produce any errors, I cannot give
  19. ** any guaranties. Neither I nor pinc Software is liable for any
  20. ** problems you might have with it.
  21. ** The usage of this example is on your own risk.
  22. */
  23.  
  24.  
  25. #define INTUI_V36_NAMES_ONLY
  26.  
  27. #include <exec/memory.h>
  28. #include <devices/input.h>
  29. #include <devices/inputevent.h>
  30. #include <intuition/intuition.h>
  31. #include <intuition/intuitionbase.h>
  32. #include <intuition/icclass.h>
  33. #include <intuition/gadgetclass.h>
  34. #include <intuition/imageclass.h>
  35. #include <intuition/sghooks.h>
  36. #include <graphics/gfx.h>
  37. #include <libraries/gadtools.h>
  38. #include <libraries/gtdrag.h>
  39.  
  40. #include <clib/console_protos.h>
  41. #include <pragmas/console_pragmas.h>
  42. #include <clib/gtdrag_protos.h>
  43. #include <pragmas/gtdrag_pragmas.h>
  44. #include <proto/exec.h>
  45. #include <proto/gadtools.h>
  46. #include <proto/intuition.h>
  47. #include <proto/graphics.h>
  48. #include <proto/utility.h>
  49.  
  50. #include <strings.h>
  51. #include <math.h>
  52.  
  53. #define reg(x) register __ ## x
  54. #define PUBLIC __saveds __asm
  55. #define bug kprintf
  56. #define foreach(l,v) for(v = (APTR)((struct List *)l)->lh_Head;((struct Node *)v)->ln_Succ;v = (APTR)((struct Node *)v)->ln_Succ)
  57. #define IsBoopsiGadget(gad) ((gad->GadgetType & GTYP_GTYPEMASK) == GTYP_CUSTOMGADGET)
  58.  
  59. void kprintf(STRPTR,...);
  60.  
  61. void processMsg(void);
  62.  
  63. struct Library *GTDragBase;
  64. struct Window *win;
  65. Class  *simplegclass;
  66. long   fontheight;
  67. struct List list;
  68.  
  69.  
  70. /********************************** Simple-Gadget **********************************/
  71.  
  72. struct SimpleGData
  73. {
  74.   struct MinList *sd_List;  /* the list to display */
  75.   ULONG  sd_Items;          /* number of items to be displayed */
  76.   ULONG  sd_Selected;       /* currently selected item */
  77.   ULONG  sd_Range;          /* width/height of an item */
  78.   ULONG  sd_CurrentDrag;    /* currently dragged item */
  79.   BOOL   sd_Direction;      /* horizontal or vertical direction? */
  80.   struct Hook *sd_Hook;     /* hook to render the items */
  81. };
  82.  
  83. #define SDD_VERTICAL 0
  84. #define SDD_HORIZONTAL 1
  85.  
  86. #define SDA_List  (TAG_USER | 0x10000)
  87. #define SDA_Items (TAG_USER | 0x10001)
  88. #define SDA_Direction (TAG_USER | 0x10002)   /* one of the SDD_### */
  89.  
  90.  
  91. /** draws the simple gadget */
  92.  
  93. void DrawSimpleGadget(struct RastPort *rp,struct Gadget *gad,struct GadgetInfo *gi,struct SimpleGData *sd,BOOL all)
  94. {
  95.   struct Node *ln;
  96.   struct LVDrawMsg lvdm;
  97.   UWORD  *pens = gi->gi_DrInfo->dri_Pens;
  98.   long   i,width,height;
  99.  
  100.   /*** draw gadget frame ***/
  101.  
  102.   if (all)
  103.   {
  104.     struct Image *im;
  105.  
  106.     if (im = NewObject(NULL,"frameiclass",IA_Width,     gad->Width,
  107.                                           IA_Height,    gad->Height,
  108.                                           IA_FrameType, FRAME_BUTTON,
  109.                                           TAG_END))
  110.     {
  111.       DrawImage(rp,im,gad->LeftEdge,gad->TopEdge);
  112.       DisposeObject(im);
  113.     }
  114.   }
  115.   width = 0;  height = 0;
  116.  
  117.   /*** render gadet contents, without any optimisations ***/
  118.  
  119.   if (sd->sd_Direction == SDD_HORIZONTAL)
  120.     width = sd->sd_Range;
  121.   else
  122.     height = sd->sd_Range;
  123.  
  124.   /* initialize listview callback render hook message */
  125.  
  126.   lvdm.lvdm_MethodID = LV_DRAW;
  127.   lvdm.lvdm_RastPort = rp;
  128.   lvdm.lvdm_DrawInfo = gi->gi_DrInfo;
  129.   lvdm.lvdm_Bounds.MinX = gad->LeftEdge+4;
  130.   lvdm.lvdm_Bounds.MinY = gad->TopEdge+4;
  131.   lvdm.lvdm_Bounds.MaxX = lvdm.lvdm_Bounds.MinX+(width ? width-1 : gad->Width-9);
  132.   lvdm.lvdm_Bounds.MaxY = lvdm.lvdm_Bounds.MinY+(height ? height-1 : gad->Height-9);
  133.   lvdm.lvdm_State = LVR_NORMAL;
  134.  
  135.   if (!sd->sd_List)
  136.     return;
  137.  
  138.   /* display the whole list */
  139.  
  140.   SetABPenDrMd(rp,pens[TEXTPEN],pens[FILLPEN],JAM2);
  141.   for(i = 0,ln = (APTR)sd->sd_List->mlh_Head;ln->ln_Succ;ln = ln->ln_Succ,i++)
  142.   {
  143.     if (i >= sd->sd_Items)
  144.       break;
  145.  
  146.     if (sd->sd_Selected == i)
  147.       lvdm.lvdm_State = LVR_SELECTED;
  148.  
  149.     CallHookPkt(sd->sd_Hook,ln,&lvdm);
  150.  
  151.     if (sd->sd_Direction == SDD_HORIZONTAL)
  152.     {
  153.       lvdm.lvdm_Bounds.MinX += width;
  154.       lvdm.lvdm_Bounds.MaxX += width;
  155.     }
  156.     else
  157.     {
  158.       lvdm.lvdm_Bounds.MinY += height;
  159.       lvdm.lvdm_Bounds.MaxY += height;
  160.     }
  161.     lvdm.lvdm_State = LVR_NORMAL;
  162.   }
  163. }
  164.  
  165. /** dispatch the OM_NEW method */
  166.  
  167. BOOL DispatchSimpleNew(struct opSet *ops,Object *o,struct SimpleGData *sd)
  168. {
  169.   SetAttrs(o,GA_Immediate,TRUE,TAG_END);
  170.   sd->sd_List = (APTR)GetTagData(SDA_List,NULL,ops->ops_AttrList);
  171.   sd->sd_Items = GetTagData(SDA_Items,1,ops->ops_AttrList);
  172.   sd->sd_Direction = GetTagData(SDA_Direction,SDD_VERTICAL,ops->ops_AttrList);
  173.   sd->sd_Hook = GTD_GetHook(GTDH_IMAGE);
  174.   sd->sd_Selected = sd->sd_CurrentDrag = ~0L;
  175.  
  176.   if (!sd->sd_Items)
  177.     return(FALSE);
  178.  
  179.   sd->sd_Range = (sd->sd_Direction == SDD_HORIZONTAL ? ((struct Gadget *)o)->Width-8 : ((struct Gadget *)o)->Height-8)/sd->sd_Items;
  180.   return(TRUE);
  181. }
  182.  
  183. /** dispatch all methods.
  184.  *
  185.  *  To mark the drag&drop related methods, these are separated
  186.  *  from the other and, furthermore, they are commented.
  187.  */
  188.  
  189. ULONG PUBLIC DispatchSimpleGadget(reg (a0) Class *cl,reg (a2) Object *o,reg (a1) Msg msg)
  190. {
  191.   struct SimpleGData *sd;
  192.   ULONG  retval = 0;
  193.  
  194.   sd = INST_DATA(cl,o);
  195.  
  196.   switch(msg->MethodID)
  197.   {
  198.     case OM_NEW:
  199.       if (retval = DoSuperMethodA(cl,o,msg))
  200.       {
  201.         sd = INST_DATA(cl,retval);
  202.  
  203.         if (!DispatchSimpleNew((struct opSet *)msg,(Object *)retval,sd))
  204.         {
  205.           DoSuperMethod(cl,(Object *)retval,OM_DISPOSE);
  206.           retval = NULL;
  207.         }
  208.       }
  209.       break;
  210.     case OM_DISPOSE:
  211.       retval = DoSuperMethodA(cl,o,msg);
  212.       break;
  213.     case OM_SET:
  214.     case OM_UPDATE:
  215.     case OM_NOTIFY:
  216.       DoSuperMethodA(cl,o,msg);
  217.       {
  218.         struct TagItem *tstate,*ti;
  219.  
  220.         tstate = ((struct opSet *)msg)->ops_AttrList;
  221.         while(ti = NextTagItem(&tstate))
  222.         {
  223.           switch(ti->ti_Tag)
  224.           {
  225.             case SDA_List:
  226.             {
  227.               struct RastPort *rp = ObtainGIRPort(((struct opUpdate *)msg)->opu_GInfo);
  228.  
  229.               sd->sd_List = (APTR)ti->ti_Data;
  230.  
  231.               DrawSimpleGadget(rp,(struct Gadget *)o,NULL,sd,FALSE);
  232.               ReleaseGIRPort(rp);
  233.               break;
  234.             }
  235.           }
  236.         }
  237.       }
  238.       break;
  239.     case OM_GET:
  240.       if (((struct opGet *)msg)->opg_AttrID == SDA_List)
  241.       {
  242.         *((struct opGet *)msg)->opg_Storage = (ULONG)sd->sd_List;
  243.         retval = TRUE;
  244.       }
  245.       else
  246.         retval = DoSuperMethodA(cl,o,msg);
  247.       break;
  248.     case GM_RENDER:
  249.       {
  250.         struct gpRender *gpr = (struct gpRender *)msg;
  251.  
  252.         DrawSimpleGadget(gpr->gpr_RPort,(struct Gadget *)o,gpr->gpr_GInfo,sd,TRUE);
  253.       }
  254.       break;
  255.     case GM_HITTEST:
  256.       retval = GMR_GADGETHIT;
  257.       break;
  258.  
  259. /*** here come drag&drop related method dispatching ***/
  260.  
  261.     case GM_OBJECTDRAG:             // do we want the object? is some further rendering needed?
  262.     {
  263.       struct gpObjectDrag *gpod = (struct gpObjectDrag *)msg;
  264.  
  265.       if ((struct Gadget *)o == gpod->gpod_Source)  // get current drag position
  266.       {
  267.         ULONG current;
  268.  
  269.         if (sd->sd_Direction == SDD_HORIZONTAL)
  270.           current = (gpod->gpod_Mouse.X-4+sd->sd_Range/2)/sd->sd_Range;
  271.         else
  272.           current = (gpod->gpod_Mouse.Y-4+sd->sd_Range/2)/sd->sd_Range;
  273.  
  274.         retval = GMR_ACCEPTOBJECT | (current != sd->sd_CurrentDrag ? GMR_UPDATE : 0);
  275.         sd->sd_CurrentDrag = current;
  276.       }
  277.       else
  278.       {
  279.         struct Gadget *gad = gpod->gpod_Source;
  280.  
  281.         if (gad && IsBoopsiGadget(gad) && OCLASS(gad) == cl) // has the source the same class then we have? (simple, no check for super-classes...)
  282.           retval = GMR_ACCEPTOBJECT;                         // we want it all
  283.         else
  284.           retval = GMR_REJECTOBJECT;
  285.  
  286.         retval |= GMR_FINAL;                // do not send this message again
  287.       }
  288.       break;
  289.     }
  290.     case GM_OBJECTDROP:
  291.       /* we do not process this method, gtdrag will send
  292.       ** the DropMessage to the window's MsgPort if we
  293.       ** return NULL, otherwise it will be catched by us.
  294.       */
  295.       break;
  296.     case GM_RENDERDRAG:
  297.     {
  298.       struct gpRenderDrag *gprd = (struct gpRenderDrag *)msg;
  299.  
  300.       /* GRENDER_HIGHLIGHT is the only one implemented here; let's
  301.       ** gtdrag do the dirty stuff.
  302.       */
  303.  
  304.       if (gprd->gprd_Mode == GRENDER_HIGHLIGHT && sd->sd_CurrentDrag != ~0L)
  305.       {
  306.         struct RastPort *rp = gprd->gprd_RPort;
  307.         struct Gadget *gad = (APTR)o;
  308.         int    current = sd->sd_CurrentDrag * sd->sd_Range;
  309.  
  310.         rp->linpatcnt = 15;  rp->Flags |= FRST_DOT;
  311.         rp->LinePtrn = 0x0f0f;
  312.         SetABPenDrMd(rp,1,2,JAM2);    // use gprd_GInfo->gi_DrInfo->dri_Pens[] instead
  313.  
  314.         if (sd->sd_Direction == SDD_HORIZONTAL)
  315.         {
  316.           Move(rp,gad->LeftEdge+current+4,gad->TopEdge+2);
  317.           Draw(rp,gad->LeftEdge+current+4,gad->TopEdge+gad->Height-3);
  318.         }
  319.         else
  320.         {
  321.           Move(rp,gad->LeftEdge+4,gad->TopEdge+3+current);
  322.           Draw(rp,gad->LeftEdge+gad->Width-4,gad->TopEdge+3+current);
  323.         }
  324.         retval = TRUE;
  325.       }
  326.       else if (gprd->gprd_Mode == GRENDER_DELETE)
  327.         sd->sd_CurrentDrag = ~0L;                 // reset temporary drag position
  328.       break;
  329.     }
  330.     case GM_GOACTIVE:
  331.     case GM_HANDLEINPUT:
  332.     {
  333.       struct gpInput *gpi = (struct gpInput *)msg;
  334.       struct InputEvent *ie = gpi->gpi_IEvent;
  335.       long x = gpi->gpi_Mouse.X, y = gpi->gpi_Mouse.Y;
  336.  
  337.       /* test if input is for us or not */
  338.  
  339.       if ((retval = GTD_HandleInput((struct Gadget *)o,gpi)) != GMR_HANDLEYOURSELF)
  340.         break;
  341.       retval = GMR_MEACTIVE;
  342.  
  343.       if (ie->ie_Class == IECLASS_RAWMOUSE)
  344.       {
  345.         if (ie->ie_Code == IECODE_RBUTTON)
  346.           retval = GMR_REUSE;
  347.         else if (ie->ie_Code == (IECODE_LBUTTON | IECODE_UP_PREFIX))
  348.         {
  349.           retval = GMR_REUSE;
  350.         }
  351.         else if (ie->ie_Code == IECODE_LBUTTON)
  352.         {
  353.           struct RastPort *rp = ObtainGIRPort(gpi->gpi_GInfo);
  354.           struct Gadget *gad = (APTR)o;
  355.  
  356.           if (sd->sd_Direction == SDD_HORIZONTAL)
  357.             sd->sd_Selected = (x-4)/sd->sd_Range;
  358.           else
  359.             sd->sd_Selected = (y-4)/sd->sd_Range;
  360.  
  361.           DrawSimpleGadget(rp,gad,gpi->gpi_GInfo,sd,FALSE);
  362.           ReleaseGIRPort(rp);
  363.         }
  364.         else if (ie->ie_Code == IECODE_NOBUTTON && GTD_PrepareDrag((struct Gadget *)o,gpi))   // mouse movement
  365.         {
  366.           struct Gadget *gad = (struct Gadget *)o;
  367.           int    i = sd->sd_Selected;
  368.           struct Node *ln;
  369.  
  370.           foreach(sd->sd_List,ln)  // get the current node
  371.           {
  372.             if (--i)
  373.               break;
  374.           }
  375.           GTD_SetAttrs(o,GTDA_Object,     ln,             // object to be dragged
  376.                          GTDA_RenderHook, sd->sd_Hook,    // use this to render the object
  377.                          GTDA_Width,      sd->sd_Direction == SDD_HORIZONTAL ? sd->sd_Range : gad->Width,
  378.                          GTDA_Height,     sd->sd_Direction == SDD_VERTICAL ? sd->sd_Range : gad->Height,
  379.                          GTDA_Type,       ODT_NODE,       // it's basically a simple node
  380.                          GTDA_Same,       TRUE,           // I want to drag&drop my objects over me
  381.                          TAG_END);
  382.           GTD_BeginDrag(gad,gpi);
  383.         }
  384.       }
  385.       break;
  386.     }
  387.     case GM_GOINACTIVE:
  388.     {
  389.       struct gpInput *gpi = (struct gpInput *)msg;
  390.       struct RastPort *rp = ObtainGIRPort(gpi->gpi_GInfo);
  391.  
  392.       GTD_StopDrag((struct Gadget *)o); // used to break the drag of an object, could also be used in other circumstances
  393.       sd->sd_Selected = ~0L;
  394.       DrawSimpleGadget(rp,(struct Gadget *)o,gpi->gpi_GInfo,sd,FALSE);
  395.       ReleaseGIRPort(rp);
  396.       break;
  397.     }
  398.     default:
  399.       retval = DoSuperMethodA(cl,o,msg);
  400.   }
  401.   return(retval);
  402. }
  403.  
  404.  
  405. /********************************** main programme **********************************/
  406.  
  407.  
  408. void processMsg(void)
  409. {
  410.   struct IntuiMessage *imsg;
  411.   ULONG  class;
  412.   UWORD  code;
  413.   BOOL   ende = FALSE;
  414.  
  415.   while(!ende)                /* simple gtdrag message loop */
  416.   {
  417.     imsg = (struct IntuiMessage *)WaitPort(win->UserPort);
  418.     while (imsg = (struct IntuiMessage *)GTD_GetIMsg(win->UserPort))
  419.     {
  420.       class = imsg->Class;
  421.       code = imsg->Code;
  422.  
  423.       switch(class)
  424.       {
  425.         case IDCMP_CLOSEWINDOW:
  426.           ende = TRUE;
  427.           break;
  428.       }
  429.       GTD_ReplyIMsg(imsg);
  430.     }
  431.   }
  432. }
  433.  
  434. /** frees the list */
  435.  
  436. void clean(void)
  437. {
  438.   struct Node *ln;
  439.  
  440.   while(ln = RemHead(&list))
  441.     FreeMem(ln,sizeof(struct ImageNode));
  442. }
  443.  
  444. const STRPTR text[] = {"abc","def","ghi","jkl","mno","pqr",NULL};
  445.  
  446. /** initializes the list to be used by the SimpleGadget */
  447.  
  448. void init(void)
  449. {
  450.   struct ImageNode *in;
  451.   int    i;
  452.  
  453.   NewList(&list);
  454.  
  455.   for(i = 0;text[i];i++)
  456.   {
  457.     if (in = AllocMem(sizeof(struct ImageNode),MEMF_CLEAR))
  458.     {
  459.       in->in_Name = text[i];
  460.       AddTail(&list,(APTR)in);
  461.     }
  462.   }
  463. }
  464.  
  465. /** initializes all stuff is needed */
  466.  
  467. void main(void)
  468. {
  469.   struct Screen *scr;
  470.   struct DrawInfo *dri;
  471.   void   *vi;
  472.   struct Gadget *hgad,*vgad;
  473.  
  474.   if (!(simplegclass = MakeClass(NULL,"gadgetclass",NULL,sizeof(struct SimpleGData),0)))
  475.     return;
  476.  
  477.   simplegclass->cl_Dispatcher.h_Entry = (ULONG (*)())DispatchSimpleGadget;
  478.  
  479.   if (GTDragBase = OpenLibrary("gtdrag.library",3))
  480.   {
  481.     if (GTD_AddApp("boopsitest",GTDA_NewStyle,TRUE,TAG_END))
  482.     {
  483.       if (scr = LockPubScreen(NULL))
  484.       {
  485.         fontheight = scr->Font->ta_YSize;
  486.         dri = GetScreenDrawInfo(scr);
  487.         init();
  488.         if (vi = GetVisualInfo(scr,TAG_END))
  489.         {
  490.           if (hgad = NewObject(simplegclass,NULL,GA_Left,       scr->WBorLeft,
  491.                                                  GA_Top,        fontheight+scr->WBorTop+1,
  492.                                                  GA_Width,      300-scr->WBorRight-scr->WBorLeft,
  493.                                                  GA_Height,     fontheight+9,
  494.                                                  SDA_List,      &list,
  495.                                                  SDA_Items,     5,
  496.                                                  SDA_Direction, SDD_HORIZONTAL,
  497.                                                  TAG_END))
  498.           {
  499.             int y;     /* fill the stack with some useless stuff */
  500.  
  501.             if (vgad = NewObject(simplegclass,NULL,GA_Left,       scr->WBorLeft,
  502.                                                    GA_Top,        y = 2*fontheight+scr->WBorTop+10,
  503.                                                    GA_Width,      40,
  504.                                                    GA_Height,     200-scr->WBorBottom-y,
  505.                                                    GA_Previous,   hgad,
  506.                                                    SDA_List,      &list,
  507.                                                    SDA_Items,     5,
  508.                                                    SDA_Direction, SDD_VERTICAL,
  509.                                                    TAG_END))
  510.             {
  511.               if (win = OpenWindowTags(NULL,WA_Title,     "gtdrag - Boopsi-Example",
  512.                                             WA_Width,     300,
  513.                                             WA_Height,    200,
  514.                                             WA_Flags,     WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE,
  515.                                             WA_IDCMP,     IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_IDCMPUPDATE | DRAGIDCMP,
  516.                                             WA_Gadgets,   hgad,
  517.                                             WA_PubScreen, scr,
  518.                                             TAG_END))
  519.               {
  520.                 processMsg();
  521.                 RemoveGList(win,hgad,-1);
  522.                 CloseWindow(win);
  523.               }
  524.               DisposeObject(vgad);
  525.             }
  526.             DisposeObject(hgad);
  527.           }
  528.           FreeVisualInfo(vi);
  529.         }
  530.         clean();
  531.         FreeScreenDrawInfo(scr,dri);
  532.         UnlockPubScreen(NULL,scr);
  533.       }
  534.       GTD_RemoveApp();
  535.     }
  536.     CloseLibrary(GTDragBase);
  537.   }
  538.   FreeClass(simplegclass);
  539. }
  540.  
  541.  
  542.